package fr.upmc.aladyn.transactionablesMetaObject;

import java.util.ArrayList;
import java.util.Collections;

import fr.upmc.aladyn.transactionables.Transactionable;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;
import javassist.Translator;
import javassist.tools.reflect.Loader;


/**
 * A translator for the meta object.
 * @author Ritchie Nithoo
 * @author Jules Fabry
 * @version 1.0
 *
 */
public class TransactionableMetaObjTranslator implements Translator {
	private Loader myLoader;

	
	/**
	 * 
	 * @param loader The loader that we need to save to be able to
	 * call the makeReflective method
	 */
	public TransactionableMetaObjTranslator(Loader loader) {
		super();
		myLoader = loader;
	}

	/**
	 * Returns a list of the name of the super-classes of a CtClass
	 * @param sc The CtClass that we want to exploit to get its superclass
	 * @return A list of the superclass of sc.
	 */
	public ArrayList<String> getListSuperClasses(CtClass sc){
		CtClass scTemp=sc;
		ArrayList<String> tab=new ArrayList<String>();
		while (scTemp.getName()!="java.lang.Object") {
			tab.add(scTemp.getName());
			try {
				scTemp=scTemp.getSuperclass();
			} catch (NotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		Collections.reverse(tab);
		return tab;
	}
	
	
	/**
	 * Intercepts classes and make them reflective if they have the annotation
	 * Also make the super classes reflective if necessary
	 */
	@Override
	public void onLoad(ClassPool pool, String className)
			throws NotFoundException, CannotCompileException {
		// System.out.println("on va rendre reflexive la classe  :"
		// + pool.getCtClass(className).getName());
		if (isTransactionable(pool, className)) {
			CtClass sc = pool.getCtClass(className).getSuperclass();
			ArrayList<String> tab=getListSuperClasses(sc);
			for (String clazz : tab){
			myLoader.makeReflective(clazz,
					"fr.upmc.aladyn.transactionablesMetaObject.SaveMetaObj",
					"javassist.tools.reflect.ClassMetaobject");
			}
			myLoader.makeReflective(className,
					"fr.upmc.aladyn.transactionablesMetaObject.SaveMetaObj",
					"javassist.tools.reflect.ClassMetaobject");
		}
	}
	
	/**
	 * The start method
	 */
	@Override
	public void start(ClassPool arg0) throws NotFoundException,
			CannotCompileException {
		// TODO Auto-generated method stub
	}

	/**
	 * Checks if the class is "transactionable" or not.
	 * @param pool The classPool
	 * @param className The class name
	 * @return The boolean to know if the method has the correct annotation
	 * @throws NotFoundException
	 */
	public boolean isTransactionable(ClassPool pool, String className)
			throws NotFoundException {
		CtClass cc = pool.get(className);
		CtMethod[] methods = cc.getDeclaredMethods();
		try {
			Object[] lesAnnotations = cc.getAnnotations();
			for (Object a : lesAnnotations) {
				if (a instanceof Transactionable) {
					return true;
				}
			}
			for (CtMethod cm : methods) {
				Object[] methodAnnotation = cm.getAnnotations();
				for (Object a : methodAnnotation) {
					if (a instanceof Transactionable) {
						return true;
					}
				}
			}
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return false;

	}
}
